package at.fhv.androideightpuzzle.activities;

import java.util.HashMap;
import java.util.Observable;
import java.util.Observer;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.Toast;
import at.fhv.androideightpuzzle.R;
import at.fhv.androideightpuzzle.application.IObserverArguments;
import at.fhv.androideightpuzzle.application.MultiPlayerClientController;
import at.fhv.androideightpuzzle.application.MultiPlayerHostController;
import at.fhv.androideightpuzzle.application.PlayPuzzleController;
import at.fhv.androideightpuzzle.application.interfaces.IPlayPuzzleController;
import at.fhv.androideightpuzzle.domain.FinishedPlayer;
import at.fhv.androideightpuzzle.domain.Position;
import at.fhv.androideightpuzzle.domain.PuzzleBoard;
import at.fhv.androideightpuzzle.puzzles.PuzzleLoader;

public class PlayPuzzleActivity extends Activity implements OnClickListener,Observer{
	
	private IPlayPuzzleController m_controller;
	
	private String m_puzzleId;
	private HashMap<ImageView,Position> m_positions;
	private ImageView[][] m_imageMatrix;
	private int[] m_imageIds;
	private boolean m_puzzleClickable;
	
	@Override
	public void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		
		m_puzzleId=getIntent().getStringExtra(IntentExtraKeys.PUZZLE_ID);
		
		m_imageIds=PuzzleLoader.loadImageIds(m_puzzleId);
		m_puzzleClickable=true;
		
		if((getIntent().getBooleanExtra(IntentExtraKeys.IS_MULTI_PLAYER_CLIENT,false)==false) &&
				(getIntent()).getBooleanExtra(IntentExtraKeys.IS_MULTI_PLAYER_HOST,false)==false){
			//create the controller
			m_controller=new PlayPuzzleController();
			m_controller.loadPuzzle(m_puzzleId);
			m_controller.shuffle();
		}else if(getIntent().getBooleanExtra(IntentExtraKeys.IS_MULTI_PLAYER_HOST,false)){
			//multi player host
			m_controller=MultiPlayerHostController.getInstance();
			((MultiPlayerHostController)m_controller).addObserver(this);
		}else{
			//multi player client
			m_controller=MultiPlayerClientController.getInstance();
			((MultiPlayerClientController)m_controller).addObserver(this);
		}
		
		setContentView(R.layout.play_puzzle);
		
		//build the hash map
		m_positions=new HashMap<ImageView,Position>();
		
		m_positions.put((ImageView)findViewById(R.id.imgPart0_0),new Position(0,0));
		m_positions.put((ImageView)findViewById(R.id.imgPart0_1),new Position(0,1));
		m_positions.put((ImageView)findViewById(R.id.imgPart0_2),new Position(0,2));
		m_positions.put((ImageView)findViewById(R.id.imgPart1_0),new Position(1,0));
		m_positions.put((ImageView)findViewById(R.id.imgPart1_1),new Position(1,1));
		m_positions.put((ImageView)findViewById(R.id.imgPart1_2),new Position(1,2));
		m_positions.put((ImageView)findViewById(R.id.imgPart2_0),new Position(2,0));
		m_positions.put((ImageView)findViewById(R.id.imgPart2_1),new Position(2,1));
		m_positions.put((ImageView)findViewById(R.id.imgPart2_2),new Position(2,2));
		
		//build the image matrix
		m_imageMatrix=new ImageView[PuzzleBoard.DIMENSION][PuzzleBoard.DIMENSION];
		
		m_imageMatrix[0][0]=(ImageView)findViewById(R.id.imgPart0_0);
		m_imageMatrix[0][1]=(ImageView)findViewById(R.id.imgPart0_1);
		m_imageMatrix[0][2]=(ImageView)findViewById(R.id.imgPart0_2);
		m_imageMatrix[1][0]=(ImageView)findViewById(R.id.imgPart1_0);
		m_imageMatrix[1][1]=(ImageView)findViewById(R.id.imgPart1_1);
		m_imageMatrix[1][2]=(ImageView)findViewById(R.id.imgPart1_2);
		m_imageMatrix[2][0]=(ImageView)findViewById(R.id.imgPart2_0);
		m_imageMatrix[2][1]=(ImageView)findViewById(R.id.imgPart2_1);
		m_imageMatrix[2][2]=(ImageView)findViewById(R.id.imgPart2_2);
		
		//add listener
		
		for(ImageView view:m_positions.keySet()){
			view.setOnClickListener(this);
		}
		
		//start (take time stamp)
		m_controller.start();
		
		Toast toast=Toast.makeText(this,R.string.solve_puzzle,Toast.LENGTH_LONG);
		toast.setGravity(Gravity.CENTER,0,0);
		toast.show();
	}
	
	@Override
	protected void onStart(){
		super.onStart();
		
		refreshParts(m_controller.getImagePositions());
	}
	
	@Override
	protected void onStop(){
		super.onStop();
		
		if(m_controller instanceof MultiPlayerClientController){
			MultiPlayerClientController.disposeInstance();
		}
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu){
		MenuInflater inflater=getMenuInflater();
		inflater.inflate(R.menu.play_puzzle_menu,menu);
		
		return true;
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item){
	    switch (item.getItemId()){
	        case R.id.menuItemShowImage:
	        	Intent intent=new Intent(this,ShowPuzzleImageActivity.class);
				intent.putExtra(IntentExtraKeys.PUZZLE_ID,m_puzzleId);
				startActivity(intent);
	            
	            return true;
	            
	        default:
	        	return true;
	    }
	}
	
	public void onClick(View view) {
		if((view instanceof ImageView) && (m_puzzleClickable==true)){
			Position position=m_positions.get(view);
			
			if(position!=null){
				refreshParts(m_controller.swapPart(position));
				
				if(m_controller.isFinished()){
					String time=formatTime(m_controller.getDuration());
					m_puzzleClickable=false;
					
					Toast toast=Toast.makeText(this,"Puzzle solved in "+time+"!",Toast.LENGTH_LONG);
					toast.setGravity(Gravity.CENTER,0,0);
					toast.show();
				}
			}
		}
	}
	
	private void refreshParts(int[][] numberMatrix){
		if(numberMatrix!=null){
			int row=0;
			int col=0;
			int dimension=PuzzleBoard.DIMENSION;
			
			while(row<dimension){
				m_imageMatrix[row][col].setImageResource(m_imageIds[numberMatrix[row][col]]);
				
				//matrix shift
				col++;
				
				if(col>=dimension){
					col=0;
					row++;
				}
			}
		}
	}
	
	public final Handler m_handler=new Handler(){
		
		@Override
		public void handleMessage(Message msg){
			if(msg.what==IHandlerMessageKeys.GAME_FINISHED){
				FinishedPlayer[] players=null;
				
				if(m_controller instanceof MultiPlayerHostController){
					players=((MultiPlayerHostController)m_controller).getRanking();
				}else if(m_controller instanceof MultiPlayerClientController){
					players=((MultiPlayerClientController)m_controller).getRanking();
				}
				
				if(players!=null){
					StringBuilder sb=new StringBuilder();
					
					for(int i=0; i<players.length; i++){
						sb.append(i).append(". ").append(players[i].getName()).append(" - ").append(formatTime(players[i].getTime())).append("\n");
					}
					
					showToast(sb.toString(),Toast.LENGTH_LONG);
				}
			}
			
			super.handleMessage(msg);
		}
	};
	
	public void update(Observable observable,Object argument){
		if(observable instanceof MultiPlayerHostController){
			if(argument.equals(IObserverArguments.GAME_FINISHED)){
				Message msg=m_handler.obtainMessage(IHandlerMessageKeys.GAME_FINISHED);
				msg.setTarget(m_handler);
				msg.sendToTarget();
			}
		}else if(observable instanceof MultiPlayerClientController){
			if(argument.equals(IObserverArguments.GAME_FINISHED)){
				Message msg=m_handler.obtainMessage(IHandlerMessageKeys.GAME_FINISHED);
				msg.setTarget(m_handler);
				msg.sendToTarget();
			}else if(argument.equals(IObserverArguments.CONNECTION_LOST)){
				Message msg=m_handler.obtainMessage(IHandlerMessageKeys.CONNECTION_LOST);
				msg.setTarget(m_handler);
				msg.sendToTarget();
			}
		}
	}
	
	public String formatTime(long seconds){
		long min=seconds/60;
		long sec=seconds%60;
		
		StringBuilder sb=new StringBuilder();
		
		sb.append(min).append(" min ");
		sb.append(sec).append(" sec");
		
		return sb.toString();
	}
	
	private void showToast(String msg,int length){
		Toast toast=Toast.makeText(this,msg,length);
		toast.setGravity(Gravity.CENTER,0,0);
		toast.show();
	}
}
